/*
  libsmtp is a library to send mail via SMTP
     This part will encode data into base64 format

     Base64 routines are borrowed from code by John Walker
		       http://www.fourmilab.ch/

Copyright � 2001 Kevin Read <obsidian@berlios.de>

This software is available under the GNU Lesser Public License as described
in the COPYING file.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

Kevin Read <obsidian@berlios.de>
Thu Aug 16 2001 */

/* This will only be included when MIME is enabled */

/* #ifndef __G_LIB_H__ */
  #include <glib.h>
/* #endif */

#define LINELEN 72		      /* Encoded line length (max 76) */

#include "../config.h"
#include <ctype.h>
#include "libsmtp.h"
#include "libsmtp_mime.h"
extern int    _write_file_email;
extern char   _log_mail_buffer[512];
#ifdef LIBSMTP_DEBUG
extern int    _log_file_email;

#endif
/* We declare some global variables *yuck* */
static unsigned char libsmtp_int_dtable[256];	      /* Encode / decode table */
static unsigned char libsmtp_int_dec_table[256];
int libsmtp_int_dtable_init=0; /* Is it initialized? */

/* This function will initialize the base64 encoding tables */

int libsmtp_int_init_base64 (void)
{
//   int libsmtp_int_temp;
//   /*	Fill dtable with character encodings.  */
//
//   for (libsmtp_int_temp = 0; libsmtp_int_temp < 26; libsmtp_int_temp++) {
//     libsmtp_int_dtable[libsmtp_int_temp] = 'A' + libsmtp_int_temp;
//     libsmtp_int_dtable[26 + libsmtp_int_temp] = 'a' + libsmtp_int_temp;
//   }
//   for (libsmtp_int_temp = 0; libsmtp_int_temp < 10; libsmtp_int_temp++) {
//     libsmtp_int_dtable[52 + libsmtp_int_temp] = '0' + libsmtp_int_temp;
//   }
//   libsmtp_int_dtable[62] = '+';
//   libsmtp_int_dtable[63] = '/';
  sprintf(libsmtp_int_dtable,"%s","ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
  sprintf(libsmtp_int_dec_table,"%s","|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq");
  libsmtp_int_dtable_init=1;

  return 0;
}

// /* This function will send data in a part, encoded in base64. It will not
//    perform any checks whatsoever. */
//
// int libsmtp_int_send_base64 (char *libsmtp_int_data, unsigned long int libsmtp_int_length, \
//          struct libsmtp_session_struct *libsmtp_session,int write)
// {
//   int libsmtp_int_temp, libsmtp_int_counter;
//
//   /* These are the input buffer and the output buffer */
//   unsigned char libsmtp_int_igroup[3], *libsmtp_int_ogroup;/*, libsmtp_int_ogroup[2056];*/
//   unsigned char libsmtp_int_char;
//   int libsmtp_int_finished=0, libsmtp_int_outbytes=0, libsmtp_int_width=0;
//   /* This points into the data stream to the byte we are reading ATM */
//   unsigned long int libsmtp_int_data_ptr=0;
//   GString *libsmtp_int_gstring=g_string_new (NULL);
//   struct libsmtp_part_struct *libsmtp_temp_part;
//
//   libsmtp_temp_part=libsmtp_session->PartNow;
//
//
//   /* Check the sizes */
//   if (libsmtp_int_length % 3)
//   {
//     #ifdef LIBSMTP_DEBUG
//       printf ("libsmtp_send_base64: size not a multiple of 3, this could make problems.\n");
//     #endif
//     /* This has to be the end of this part */
//     libsmtp_temp_part->Base64_finished = 1;
//   }
//   else
//   {
// //     if (libsmtp_temp_part->Base64_finished)
// //     {
// //       #ifdef LIBSMTP_DEBUG
// //         printf ("libsmtp_send_base64: Already had a chunk for this part that was not a multiple of 3 in length. Cannot Append to it in Base64.\n");
// //       #endif
// //       /*After we already had an ending chunk for this part, we cannot go on */
// //       return LIBSMTP_BASE64WRONGSIZE;
// //     }
//   }
//
//
//   if (!libsmtp_int_dtable_init)
//     libsmtp_int_init_base64();
//   libsmtp_int_ogroup = (unsigned char*)malloc(/*libsmtp_int_length*/2056*sizeof(unsigned char));
//   /* The main parsing loop */
//   while (!libsmtp_int_finished)
//   {
//     /* We now fetch 3 bytes from the input data */
//     libsmtp_int_igroup[0] = libsmtp_int_igroup[1] = libsmtp_int_igroup[2] = 0;
//     for (libsmtp_int_counter = 0; libsmtp_int_counter < 3; \
//          libsmtp_int_counter++)
//     {
//       libsmtp_int_char = libsmtp_int_data[libsmtp_int_data_ptr++];
//
//       /* Lets check that we don't read over the end of the input buffer */
//       if (libsmtp_int_data_ptr > libsmtp_int_length+1)
//       {
//         libsmtp_int_finished = 1;
//         break;
//       }
//
//       /* Assign the fetched data to the input buffer. This could all be
//          optimized */
//       libsmtp_int_igroup[libsmtp_int_counter] = (unsigned char) libsmtp_int_char;
//     }
//
//     /* Only encode if we have fetched any bytes */
//     if (libsmtp_int_counter > 0)
//     {
//       /* This is the encoding stuff - courtesy of John Walker */
//       libsmtp_int_ogroup[libsmtp_int_outbytes] = libsmtp_int_dtable[libsmtp_int_igroup[0] >> 2];
//       libsmtp_int_ogroup[libsmtp_int_outbytes+1] = libsmtp_int_dtable[((libsmtp_int_igroup[0] & 3) << 4) | (libsmtp_int_igroup[1] >> 4)];
//       libsmtp_int_ogroup[libsmtp_int_outbytes+2] = libsmtp_int_dtable[((libsmtp_int_igroup[1] & 0xF) << 2) | (libsmtp_int_igroup[2] >> 6)];
//       libsmtp_int_ogroup[libsmtp_int_outbytes+3] = libsmtp_int_dtable[libsmtp_int_igroup[2] & 0x3F];
//
//       /* Replace characters in output stream with "=" pad
//          characters if fewer than three characters were
//          read from the end of the input stream. */
//
//       if (libsmtp_int_counter < 3)
//       {
//         libsmtp_int_ogroup[libsmtp_int_outbytes+3] = '=';
//         if (libsmtp_int_counter < 2)
//         {
//           libsmtp_int_ogroup[libsmtp_int_outbytes+2] = '=';
//         }
//       }
//       libsmtp_int_outbytes+=4;
//       libsmtp_int_width+=4;
//
//       /* After 72 characters in a line we need a linebreak */
//       if (libsmtp_int_width > 72 )
//       {
//         libsmtp_int_ogroup[libsmtp_int_outbytes++]='\r';
//         libsmtp_int_ogroup[libsmtp_int_outbytes++]='\n';
//         libsmtp_int_width=0;
//       }
//
//       /* If we have more than 2K of data, we send it */
//       if (libsmtp_int_outbytes >=2048)
//       {
// /*        libsmtp_int_ogroup[libsmtp_int_outbytes]='\0';  */
// /*        libsmtp_int_outbytes--; */
//         if (libsmtp_int_send_body (libsmtp_int_ogroup, libsmtp_int_outbytes, libsmtp_session,write)){
//           free(libsmtp_int_ogroup);
// 	 return LIBSMTP_ERRORSENDFATAL;
//         }
//
//         #ifdef LIBSMTP_DEBUG
//           printf ("libsmtp_send_base64: out: %s\n", libsmtp_int_ogroup);
//         #endif
//         /* We reset the pointer into our outbuffer, too */
//         libsmtp_int_outbytes=0;
//       }
//     }
//   }
//
//   /* We send the rest of the data out anyway. It is better to send a linebreak
//      here so the next pack won't go over 72 characters a line */
// //   if(libsmtp_temp_part->Subtype != LIBSMTP_MIME_SUB_PDF){
//   libsmtp_int_ogroup[libsmtp_int_outbytes++]='\r';
//   libsmtp_int_ogroup[libsmtp_int_outbytes++]='\n';
//   libsmtp_int_ogroup[libsmtp_int_outbytes]='\0';
//   if (libsmtp_int_send_body (libsmtp_int_ogroup, libsmtp_int_outbytes, libsmtp_session,write)){
//           free(libsmtp_int_ogroup);
// 	 return LIBSMTP_ERRORSENDFATAL;
//         }
// //    }
//   #ifdef LIBSMTP_DEBUG
//     printf ("libsmtp_send_base64: out: %s\n", libsmtp_int_ogroup);
//     printf ("subtype: [%d] type:[%d]\n", libsmtp_temp_part->Subtype,libsmtp_temp_part->Type);
//   #endif
//    free(libsmtp_int_ogroup);
//   return LIBSMTP_NOERR;
// }
/* This function will send data in a part, encoded in base64. It will not
   perform any checks whatsoever. */

int libsmtp_int_send_base64 (char *libsmtp_int_data, unsigned long int libsmtp_int_length, \
         struct libsmtp_session_struct *libsmtp_session,int write)
{
  int libsmtp_int_temp, libsmtp_int_counter;

  /* These are the input buffer and the output buffer */
  unsigned char libsmtp_int_igroup[3], *libsmtp_int_ogroup;/*, libsmtp_int_ogroup[2056];*/
  unsigned char libsmtp_int_char;
  int libsmtp_int_finished=0, libsmtp_int_outbytes=0, libsmtp_int_width=0;
  /* This points into the data stream to the byte we are reading ATM */
  unsigned long int libsmtp_int_data_ptr=0;
  GString *libsmtp_int_gstring=g_string_new (NULL);

  struct libsmtp_part_struct *libsmtp_temp_part;

  libsmtp_temp_part=libsmtp_session->PartNow;


  /* Check the sizes */
  if (libsmtp_int_length % 3)
  {
    #ifdef LIBSMTP_DEBUG
      printf ("libsmtp_send_base64: size not a multiple of 3, this could make problems.\n");
    #endif
    /* This has to be the end of this part */
    libsmtp_temp_part->Base64_finished = 1;
  }



  if (!libsmtp_int_dtable_init)
    libsmtp_int_init_base64();
  libsmtp_int_ogroup = (unsigned char*)calloc((libsmtp_int_length+3)*2,sizeof(unsigned char));
  /* The main parsing loop */
  while (!libsmtp_int_finished)
  {
    /* We now fetch 3 bytes from the input data */
    libsmtp_int_igroup[0] = libsmtp_int_igroup[1] = libsmtp_int_igroup[2] = 0;
    for (libsmtp_int_counter = 0; libsmtp_int_counter < 3; \
         libsmtp_int_counter++)
    {
      libsmtp_int_char = libsmtp_int_data[libsmtp_int_data_ptr++];

      /* Lets check that we don't read over the end of the input buffer */
      if (libsmtp_int_data_ptr > libsmtp_int_length+1)
      {
        libsmtp_int_finished = 1;
        break;
      }

      /* Assign the fetched data to the input buffer. This could all be
         optimized */
      libsmtp_int_igroup[libsmtp_int_counter] = (unsigned char) libsmtp_int_char;
    }

    /* Only encode if we have fetched any bytes */
    if (libsmtp_int_counter > 0)
    {

//     out[0] = cb64[ in[0] >> 2 ];
//     out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
//     out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=');
//     out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '=');

//       char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
//       char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
//       char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
//       char_array_4[3] = char_array_3[2] & 0x3f;

//       libsmtp_int_ogroup[libsmtp_int_outbytes] = libsmtp_int_dtable[libsmtp_int_igroup[0] >> 2];
//       libsmtp_int_ogroup[libsmtp_int_outbytes+1] = libsmtp_int_dtable[((libsmtp_int_igroup[0] & 3) << 4) | (libsmtp_int_igroup[1] >> 4)];
//       libsmtp_int_ogroup[libsmtp_int_outbytes+2] = libsmtp_int_dtable[((libsmtp_int_igroup[1] & 0xF) << 2) | (libsmtp_int_igroup[2] >> 6)];
//       libsmtp_int_ogroup[libsmtp_int_outbytes+3] = libsmtp_int_dtable[libsmtp_int_igroup[2] & 0x3F];

      /* This is the encoding stuff - courtesy of John Walker  new*/
//       libsmtp_int_ogroup[libsmtp_int_outbytes] = libsmtp_int_dtable[libsmtp_int_igroup[0] >> 2];
//       libsmtp_int_ogroup[libsmtp_int_outbytes+1] = \
// 	libsmtp_int_dtable[((libsmtp_int_igroup[0] & 0x03) << 4) + ((libsmtp_int_igroup[1] & 0xf0)>> 4)];
//       libsmtp_int_ogroup[libsmtp_int_outbytes+2] = \
// 	(unsigned char) ((libsmtp_int_counter >1  ) ? libsmtp_int_dtable[((libsmtp_int_igroup[1] & 0x0f) << 2) + ((libsmtp_int_igroup[2] & 0xc0) >> 6)] : '=' );
//       libsmtp_int_ogroup[libsmtp_int_outbytes+3] = (unsigned char) ((libsmtp_int_counter >2 ) ? libsmtp_int_dtable[libsmtp_int_igroup[2] & 0x3f] : '=');
// originale
      libsmtp_int_ogroup[libsmtp_int_outbytes] = libsmtp_int_dtable[libsmtp_int_igroup[0] >> 2];
      libsmtp_int_ogroup[libsmtp_int_outbytes+1] = \
	libsmtp_int_dtable[((libsmtp_int_igroup[0] & 3) << 4) | (libsmtp_int_igroup[1] >> 4)];
      libsmtp_int_ogroup[libsmtp_int_outbytes+2] = \
	(unsigned char) ((libsmtp_int_counter >1  ) ? libsmtp_int_dtable[((libsmtp_int_igroup[1] & 0xF) << 2) | (libsmtp_int_igroup[2]  >> 6)] : '=' );
      libsmtp_int_ogroup[libsmtp_int_outbytes+3] = (unsigned char) ((libsmtp_int_counter >2 ) ? libsmtp_int_dtable[libsmtp_int_igroup[2] & 0x3F] : '=');

      /* Replace characters in output stream with "=" pad
         characters if fewer than three characters were
         read from the end of the input stream. */


      libsmtp_int_outbytes+=4;
      libsmtp_int_width+=4;

      /* After 72 characters in a line we need a linebreak */
      if (libsmtp_int_width > 72 )
      {
        libsmtp_int_ogroup[libsmtp_int_outbytes++]='\r';
        libsmtp_int_ogroup[libsmtp_int_outbytes++]='\n';
        libsmtp_int_width=0;
      }

      /* If we have more than 2K of data, we send it */
//       if (libsmtp_int_outbytes >=2048)
//       {
// /*        libsmtp_int_ogroup[libsmtp_int_outbytes]='\0';  */
// /*        libsmtp_int_outbytes--; */
//         if (libsmtp_int_send_body (libsmtp_int_ogroup, libsmtp_int_outbytes, libsmtp_session,write)){
//           free(libsmtp_int_ogroup);
// 	 return LIBSMTP_ERRORSENDFATAL;
//         }
//
//         #ifdef LIBSMTP_DEBUG
//           printf ("libsmtp_send_base64: out: %s\n", libsmtp_int_ogroup);
//         #endif
//         /* We reset the pointer into our outbuffer, too */
//         libsmtp_int_outbytes=0;
//       }
    }
  }

  /* We send the rest of the data out anyway. It is better to send a linebreak
     here so the next pack won't go over 72 characters a line */

  libsmtp_int_ogroup[libsmtp_int_outbytes++]='\r';
  libsmtp_int_ogroup[libsmtp_int_outbytes++]='\n';
  libsmtp_int_ogroup[libsmtp_int_outbytes]='\0';
  if (libsmtp_int_send_body (libsmtp_int_ogroup, libsmtp_int_outbytes, libsmtp_session,write)){
          free(libsmtp_int_ogroup);
          g_string_free (libsmtp_int_gstring,1);
	 return LIBSMTP_ERRORSENDFATAL;
        }

  #ifdef LIBSMTP_DEBUG
    printf ("libsmtp_send_base64: out: %s\n", libsmtp_int_ogroup);
    printf ("subtype: [%d] type:[%d]\n", libsmtp_temp_part->Subtype,libsmtp_temp_part->Type);
  #endif
   free(libsmtp_int_ogroup);
   g_string_free (libsmtp_int_gstring,1);
  return LIBSMTP_NOERR;
}

int libsmtp_string_encode_base64 (char * input,char *output){

    int libsmtp_int_counter,libsmtp_int_finished=0,libsmtp_int_width=0;
    unsigned long int inizio=0,libsmtp_int_outbytes=0;
    unsigned char libsmtp_int_char;
    unsigned char libsmtp_int_igroup[3];

   if (!libsmtp_int_dtable_init)  libsmtp_int_init_base64();

    while(!libsmtp_int_finished){
	for(libsmtp_int_counter=0;libsmtp_int_counter<3;libsmtp_int_counter++){

	libsmtp_int_char = input[inizio++];

	/* Lets check that we don't read over the end of the input buffer */
	if (inizio>strlen(input))
	{
		libsmtp_int_finished = 1;
		break;
	}

	/* Assign the fetched data to the input buffer. This could all be
		optimized */
	libsmtp_int_igroup[libsmtp_int_counter] = (unsigned char) libsmtp_int_char;

	}


        if(libsmtp_int_counter>0){
      output[libsmtp_int_outbytes] = libsmtp_int_dtable[libsmtp_int_igroup[0] >> 2];
      output[libsmtp_int_outbytes+1] = libsmtp_int_dtable[((libsmtp_int_igroup[0] & 3) << 4) | (libsmtp_int_igroup[1] >> 4)];
      output[libsmtp_int_outbytes+2] = (unsigned char) ((libsmtp_int_counter >1  ) ? libsmtp_int_dtable[((libsmtp_int_igroup[1] & 0xF) << 2) | (libsmtp_int_igroup[2]  >> 6)] : '=' );
      output[libsmtp_int_outbytes+3] = (unsigned char) ((libsmtp_int_counter >2 ) ? libsmtp_int_dtable[libsmtp_int_igroup[2] & 0x3F] : '=');


      libsmtp_int_outbytes+=4;
      libsmtp_int_width+=4;

      /* After 72 characters in a line we need a linebreak */
      if (libsmtp_int_width > 72 )
      {
        output[libsmtp_int_outbytes++]='\r';
        output[libsmtp_int_outbytes++]='\n';
        libsmtp_int_width=0;
      }


      }
     }
     return 1;
}

int is_base64(unsigned char c) {
  return (isalnum(c) || (c == '+') || (c == '/'));
}

int findChar(unsigned char c){
int kk;
	for(kk=0;kk<strlen(libsmtp_int_dtable);kk++){
		if(libsmtp_int_dtable[kk]==c){
			return kk+1;
		}
	}
	return kk+1;
}

void decodeblock( unsigned char in[4], unsigned char out[3] )
{
    out[ 0 ] = (unsigned char ) (in[0] << 2 | in[1] >> 4);
    out[ 1 ] = (unsigned char ) (in[1] << 4 | in[2] >> 2);
    out[ 2 ] = (unsigned char ) (((in[2] << 6) & 0xc0) | in[3]);
}

int libsmtp_string_decode_base64 (char * input,char *output){

//   unsigned long int in_len = strlen(input),out=0,in_ = 0;
//   int i = 0;
//   int j = 0;
//   unsigned char char_array_4[4], char_array_3[3];
//   libsmtp_int_init_base64();
//
//   while (in_len-- && ( input[in_] != '=') && is_base64(input[in_])) {
//     char_array_4[i++] = input[in_]; in_++;
//     if (i ==4) {
//       for (i = 0; i <4; i++)
//         char_array_4[i] = findChar(char_array_4[i]);
//
//       char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
//       char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
//       char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
//
//       for (i = 0; (i < 3); i++)
//         output[out++]=char_array_3[i];
//       i = 0;
//     }
//   }
//
//   if (i) {
//     for (j = i; j <4; j++)
//       char_array_4[j] = 0;
//
//     for (j = 0; j <4; j++)
//       char_array_4[j] = findChar(char_array_4[j]);
//
//     char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
//     char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
//     char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
//
//     for (j = 0; (j < i - 1); j++) output[out++] = char_array_3[j];
//   }
//   output[out++]='\0';
//   return out;

    unsigned long int in_len = strlen(input)-1,in_ = 0,out_cnt=0;
    unsigned char in[4], out[3], v;
    int i, len;

    while( in_len>0 ){
    if(input[in_len]=='\r'||input[in_len]=='\n'||input[in_len]=='\0')input[in_len]='\0';
    else break;
    in_len--;
     }
    in_len = strlen(input);
    while( in_<in_len ) {
        for( len = 0, i = 0; i < 4 && in_<in_len; i++ ) {
            v = 0;
            while( in_<in_len && v == 0 ) {
                v = (unsigned char) input[in_++];
                v = (unsigned char) ((v < 43 || v > 122) ? 0 : libsmtp_int_dec_table[ v - 43 ]);
                if( v ) {
                    v = (unsigned char) ((v == '$') ? 0 : v - 61);
                }
            }
            if( in_<in_len ) {
                len++;
                if( v ) {
                    in[ i ] = (unsigned char) (v - 1);
                }
            }
            else {
                in[i] = 0;
            }
        }
        if( len ) {
            decodeblock( in, out );
            for( i = 0; i < len - 1; i++ ) {
                output[out_cnt+i]=out[i];
            }
            out_cnt+=len-1;
        }
    }
    output[out_cnt]='\0';

}

